﻿using System;
using System.Collections;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Reflection;

namespace xxpl.HTTP
{
    class ServiceInfoHandler : IHttpRequestHandler
    {
        public void Execute(HttpListenerRequest request, HttpListenerResponse response)
        {
            StreamWriter sw = new StreamWriter(response.OutputStream);
            sw.WriteLine("<html>");
            Hashtable sHashtable = AccessStaticField<Hashtable>(typeof(ServicePointManager), "s_ServicePointTable");
            foreach (DictionaryEntry entry in sHashtable)
            {
                sw.WriteLine("<h>Service point: {0}<h><br/><hr/>", entry.Key);
                WeakReference servicePointRef = (WeakReference)entry.Value;

                if (servicePointRef == null || !servicePointRef.IsAlive || servicePointRef.Target == null) continue;

                ServicePoint servicePoint = (ServicePoint)servicePointRef.Target;

                sw.WriteLine("<h>Current Connections: {0}<h><br/>", servicePoint.CurrentConnections);

                Hashtable hashtable = AccessField<Hashtable>(servicePoint, "m_ConnectionGroupList");
                foreach (DictionaryEntry dictionaryEntry in hashtable)
                {
                    sw.WriteLine("<h>Connection Group: {0} <h><br/>", dictionaryEntry.Key);
                    sw.WriteLine("<table border=1><tr><th>From</th><th>to</th></tr>");
                    var connGroup = dictionaryEntry.Value;
                    ArrayList arrayList = AccessField<ArrayList>(connGroup, "m_ConnectionList");
                    foreach (var conn in arrayList)
                    {
                        NetworkStream networkStream = AccessField<NetworkStream>(conn, "m_NetworkStream");
                        bool isDisposed = AccessField<bool>(networkStream, "m_CleanedUp");
                        if (isDisposed) continue;
                        Socket socket = AccessProperty<Socket>(networkStream, "Socket");
                        if (socket != null)
                        {
                            sw.WriteLine("<tr><td>{0}</td><td>{1}</td></tr>", socket.LocalEndPoint, socket.RemoteEndPoint);
                        }
                    }
                    sw.WriteLine("</table><br/>");
                }
            }
            sw.WriteLine("</html>");
            sw.Flush();
            sw.Close();
            response.Close();
        }



        private static T AccessField<T>(object instance, string property)
        {
            Type type = instance.GetType();
            FieldInfo fieldInfo = null;

            while (fieldInfo == null && type != null)
            {
                fieldInfo = type.GetField(property, BindingFlags.NonPublic | BindingFlags.Instance);
                type = type.BaseType;
            }

            return (T)fieldInfo.GetValue(instance);
        }

        private static T AccessProperty<T>(object instance, string property)
        {
            Type type = instance.GetType();
            PropertyInfo propertyInfo = null;

            while (propertyInfo == null && type != null)
            {
                propertyInfo = type.GetProperty(property, BindingFlags.NonPublic | BindingFlags.Instance);
                type = type.BaseType;
            }

            return (T)propertyInfo.GetValue(instance, null);
        }

        private static T AccessStaticField<T>(Type type, string property)
        {
            FieldInfo fieldInfo = type.GetField(property, BindingFlags.NonPublic | BindingFlags.Static);
            return (T)fieldInfo.GetValue(null);
        }
    }
}
